/** 应用程序配置类
 * @file config.cpp
 * @author Kiven Lee
 * @version 1.0
 * @date 2021-08-09
 *
 * @copyright Copyright Kivensoft (c) 2021
 *
 */
#include "app.hpp"

#include <charconv>

#include "klib/argparse.hpp"
#include "klib/log.hpp"
#include "klib/utils.hpp"
#include "klib/file.hpp"

using namespace klib;

// 常量定义
namespace {

    const char DEF_LOG_FILE[]           = "";
    const char DEF_LOG_LEVEL[]          = "debug";
    const char DEF_LOG_SIZE[]           = "10m";
    const char DEF_WORK[]               = "";
    const char DEF_LISTEN[]             = "0.0.0.0:8000";
    const char DEF_SHUTDOWN_PASS[]      = "";

    const char STATIC_DIR[]             = "static";
    const char COPY_RIGHT[]             = "Kivensoft 2017-2021";

    const char ARG_DEBUG[]              = "debug";
    const char ARG_HELP[]               = "help";
    const char ARG_NO_COLOR[]           = "no-color";
    const char ARG_LISTEN[]             = "listen";
    const char ARG_SHUTDOWN_PASS[]      = "shutdown-pass";
    const char ARG_LOG_FILE[]           = "log-file";
    const char ARG_LOG_LEVEL[]          = "log-level";
    const char ARG_LOG_SIZE[]           = "log-size";
    const char ARG_WORK[]               = "work";

    const char CONF_DIR[]               = "";
    const char CONF_EXT[]               = ".conf";
}

using OPT = klib::opt_flag_t;
static constinit arg_option_t gArgOptons[] = {
    // 选项参数标志 短选项  长选项，           缺省值              说明
    {OPT::NoArg,    'd',    ARG_DEBUG,         nullptr,            "设置为调试模式"},
    {OPT::NoArg,    'h',    ARG_HELP,          nullptr,            "打印帮助信息并退出"},
    {OPT::NoArg,    '\0',   ARG_NO_COLOR,      nullptr,            "禁用控制台色彩"},
    {OPT::HasArg,   'l',    ARG_LISTEN,        DEF_LISTEN,         "服务监听地址"},
    {OPT::HasArg,   'p',    ARG_SHUTDOWN_PASS, DEF_SHUTDOWN_PASS,  "远程关闭应用口令"},
    {OPT::HasArg,   'F',    ARG_LOG_FILE,      DEF_LOG_FILE,       "设置日志文件名(example: " AC_Y("logs/accinfo.log") ")"},
    {OPT::HasArg,   'L',    ARG_LOG_LEVEL,     DEF_LOG_LEVEL,      "设置日志级别[trace/debug/info/warn/error/off]"},
    {OPT::HasArg,   '\0',   ARG_LOG_SIZE,      DEF_LOG_SIZE,       "设置日志文件大小[k/m/g]"},
    {OPT::HasArg,   'w',    ARG_WORK,          DEF_WORK,           "设置工作目录(default: " AC_Y("<CURRENT DIRECTIRY>") ")"},
};


static constexpr char applogo[] = R"(
                   _       ____
  ____ _kivensoft_(_)___  / __/___
 / __ `/ ___/ ___/ / __ \/ /_/ __ \
/ /_/ / /__/ /__/ / / / / __/ /_/ /
\__,_/\___/\___/_/_/ /_/_/  \____/

)";

// 彩色输出一行
static void _print_color_line(int color_index, const char* line, std::size_t line_size) {
    if (line_size > 1 || *line != '\n') {
        char c[] = {"\x1b[30m"};
        c[3] = (char) (color_index + 0x31);
        std::fwrite(c, 1, 5, stdout);
        std::fwrite(line, 1, line_size, stdout);
        std::fwrite("\x1b[0m", 1, 4, stdout);
        std::fflush(stdout);
    } else {
        std::putchar('\n');
    }
}

static void _get_conf_name(dstring_t<>& out, std::string_view app) {
    if (!sizeof(CONF_DIR) || CONF_DIR[0] != '/') {
        out.append(path::base_path(app)).push_back('/');
        if (sizeof(CONF_DIR))
            out.append(CONF_DIR).push_back('/');
    } else {
        out.append(CONF_DIR).push_back('/');
    }
    out.append(path::file_no_ext(path::base_file(app)))
        .append(CONF_EXT);
}

bool ai::app::parse(int argc, char* const argv[]) {
    using namespace ai::app::_detail;
    dstring_t tmp_str;

    // 获取配置文件路径
    _get_conf_name(tmp_str, argv[0]);
    
    app_conf_t ac(gArgOptons, app::name, tmp_str.data());

    if (!ac.arg_parse.parse(argc, argv) || ac.arg_parse.is_set(ARG_HELP)) {
        dstring_t title(FC_Y " version " FC_G "\nCopyRight (C) Kivensoft 2017-2021\n" FC_C,
            name, ver, desc);
        ac.arg_parse.usage(title.c_str(), name);
        return false;
    }

    _debug = ac.get_bool(ARG_DEBUG, false);
    _listen = ac.get_string_view(ARG_LISTEN, DEF_LISTEN);
    _work = ac.get_string_view(ARG_WORK, DEF_WORK);
    _shutdown_pass = ac.get_string_view(ARG_SHUTDOWN_PASS, DEF_SHUTDOWN_PASS);

    // 按平台修正路径的分隔符
    klib::path::fix_path_spec(_work);

    // 设置日志是否支持ansi彩色
    if (ac.get_bool(ARG_NO_COLOR, false))
        klib::log::disable_color();

    // 设置日志级别及输出的日志文件
    klib::log::set_level(ac.get_string_view(ARG_LOG_LEVEL, DEF_LOG_LEVEL));
    tmp_str.clear();
    tmp_str.append(ac.get_string_view(ARG_LOG_FILE, DEF_LOG_FILE));
    if (tmp_str)
        klib::log::set_file(tmp_str.c_str(),
                (uint32_t) ac.get_int(ARG_LOG_SIZE, arg_parse_t::to_number(DEF_LOG_SIZE)));

    return true;
}

// 输出logo
void ai::app::show_logo() {
    std::srand(std::time(nullptr));
    const char* p = applogo, *e;

    // 每一行用随机颜色打印
    for (; (e = std::strchr(p, '\n')); p = e + 1)
        _print_color_line(std::rand() % 7, p, e + 1 - p);

    // 处理最后一行
    if (*p)
        _print_color_line(std::rand() % 7, p, std::strlen(p));

    // 应用程序信息
    fmt::print("\n" FC_G " ver " FC_Y " Copyright (C) "
            AC_M("Kivensoft") " 2018-2021\n{}\n\n", name, ver, desc);
}
